﻿using FCSChart.Graphical;
using System;
using System.Collections.Generic;
using System.Windows.Media;

namespace FCSChart
{
    public static class Helper
    {
        internal static readonly Color DefaultColor = new Color() { A = 0xff, R = 0x00, G = 0x90, B = 0xff };
        internal static readonly Brush DefaultSeriesFill = new SolidColorBrush(DefaultColor);

        static readonly Random random = new Random();
        /// <summary>
        /// 获取新的颜色
        /// </summary>
        /// <returns></returns>
        public static Color GetNewColor(byte a = 0xff)
        {
            byte r = Convert.ToByte(random.Next(255));
            byte g = Convert.ToByte(random.Next(255));
            byte b = Convert.ToByte(random.Next(255));
            return new Color() { A = a, R = r, G = g, B = b };
        }
        /// <summary>
        /// 获取新的笔刷
        /// </summary>
        /// <returns></returns>
        public static SolidColorBrush GetNewSolidColorBrush(byte a = 0xff)
        {
            return new SolidColorBrush(GetNewColor(a));
        }

        /// <summary>
        /// 获取渐变颜色
        /// </summary>
        /// <param name="i">当前梯度值</param>
        /// <param name="max">最大梯度量</param>
        /// <param name="color">基础颜色</param>
        public static Color GetGradientColor(long i, long max)
        {
            if (i == 0) return Color.FromArgb(0xff, 0x00, 0x00, 0xff);
            else if (i == max) return Color.FromArgb(0xff, 0xff, 0x00, 0x00);
            var temp = max / 4d;
            var c = i / temp;
            var y = i % temp;
            if (c >= 0 && c < 1)
            {
                byte r = 0x00;
                byte g = Convert.ToByte(y * 0xff / temp);
                byte b = 0xff;
                return Color.FromArgb(0xff, r, g, b);
            }
            else if (c >= 1 && c < 2)
            {
                byte r = 0x00;
                byte g = 0xff;
                byte b = Convert.ToByte(0xff - y * 0xff / temp);
                return Color.FromArgb(0xff, r, g, b);
            }
            else if (c >= 2 && c < 3)
            {
                byte r = Convert.ToByte(y * 0xff / temp);
                byte g = 0xff;
                byte b = 0x00;
                return Color.FromArgb(0xff, r, g, b);
            }
            else
            {
                byte r = 0xff;
                byte g = Convert.ToByte(0xff - y * 0xff / temp);
                byte b = 0x00;
                return Color.FromArgb(0xff, r, g, b);
            }

        }
        /// <summary>
        /// decimal转字符串
        /// 数字过大时用科学计数法
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string ToShortString(this decimal value)
        {
            int i = 0;
            var temp = value;
            while (Math.Abs(temp / 10) >= 1)
            {
                temp /= 10;
                i++;
            }
            var tempStr = string.Concat(temp, "E+", i);
            var tempStr1 = value.ToString();
            return tempStr.Length > tempStr1.Length ? tempStr1 : tempStr;
        }

        /// <summary>
        /// 已使用的区域名称集合
        /// </summary>
        public static Dictionary<string, int> GraphicalNameIndex { get; } = new Dictionary<string, int>();
        /// <summary>
        /// 创建新门的名称
        /// </summary>
        /// <param name="graphical"></param>
        /// <returns></returns>
        internal static string CreateNewNameFaction(BaseGraphical graphical)
        {
            if (!GraphicalNameIndex.ContainsKey(graphical.ShortName)) GraphicalNameIndex[graphical.ShortName] = 0;
            GraphicalNameIndex[graphical.ShortName]++;
            return string.Concat(graphical.ShortName, GraphicalNameIndex[graphical.ShortName]);
        }

        /// <summary>
        /// 添加已存在的区域名称
        /// </summary>
        /// <param name="name"></param>
        internal static void AddExistedGraphicalName(string shortName, params string[] areaNames)
        {
            if (string.IsNullOrEmpty(shortName) || areaNames == null || areaNames.Length <= 0) return;
            foreach (var areaName in areaNames)
            {
                if (string.IsNullOrEmpty(areaName) || !areaName.StartsWith(shortName)) continue;
                var number = areaName.Substring(shortName.Length);
                if (int.TryParse(number, out int n))
                {
                    if (GraphicalNameIndex.ContainsKey(shortName) && GraphicalNameIndex[shortName] <= n) GraphicalNameIndex[shortName] = n;
                    else if (!GraphicalNameIndex.ContainsKey(shortName)) GraphicalNameIndex[shortName] = n;
                }
            }
        }

        #region 内置的轴函数算法
        public static double Log10(double value)
        {
            if (double.IsNaN(value)) return value;
            else if (double.IsPositiveInfinity(value)) return double.MaxValue;
            else if (double.IsNegativeInfinity(value)) return double.MinValue;
            else if (value >= 10) return Math.Log10(value);
            else if (value <= -10) return -Math.Log10(-value);
            else return value / 10;
        }

        public static double Pow10(double value)
        {
            if (double.IsNaN(value)) return value;
            else if (double.IsPositiveInfinity(value)) return double.MaxValue;
            else if (double.IsNegativeInfinity(value)) return double.MinValue;
            else if (value >= 1) return Math.Pow(10, value);
            else if (value <= -1) return -Math.Pow(10, -value);
            else return value * 10;
        }

        /// <summary>
        /// 双指数
        /// y=ln(sqrt((x-4.607)^2/4+1141)+(x-4.607)/2)/2.3026
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static double LogBiExp(double value)
        {
            if (double.IsNaN(value)) return value;
            else if (double.IsPositiveInfinity(value)) return double.MaxValue;
            else if (double.IsNegativeInfinity(value)) return double.MinValue;
            else
            {
                var temp = value - 4.607;
                return Math.Log(Math.Sqrt(Math.Pow(temp, 2) / 4 + 1141) + temp / 2) / 2.3026;
            }
        }

        /// <summary>
        /// y= (exp(2*2.3026*x)-1141)/(exp(2.3026*x))+4.607
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static double PowBiExp(double value)
        {
            if (double.IsNaN(value)) return value;
            else if (double.IsPositiveInfinity(value)) return double.MaxValue;
            else if (double.IsNegativeInfinity(value)) return double.MinValue;
            else
            {
                var temp = 2.3026 * value;
                return (Math.Exp(2 * temp) - 1141) / Math.Exp(temp) + 4.607;
            }
        }

        #endregion
    }
}
